home *** CD-ROM | disk | FTP | other *** search
/ QuickTime 2.0 Developer Kit / QuickTime 2.0 Developer Kit.iso / mac / MAC / Programming Stuff / Sample Code / Codecs / DrawTextCodec / DrawTextComponent.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-09  |  25.4 KB  |  865 lines  |  [TEXT/KAHL]

  1. /*
  2.  
  3.     Written by:    Mark Krueger
  4.  
  5.     Copyright:    © 1992 by Apple Computer, Inc., all rights reserved.
  6.  
  7. */
  8.  
  9. #include <Memory.h>
  10. #include <Resources.h>
  11. #include <QuickDraw.h>    
  12. #include <QDOffscreen.h>
  13. #include <OSUtils.h>
  14. #include <Errors.h>
  15. #include <FixMath.h>
  16.  
  17. #include "ImageCodec.h"
  18.  
  19. #include    "DrawTextCodec.h"
  20.  
  21. extern long
  22. Decompress(char *baseAddr,short rowBytes,short bwidth,short bheight,
  23.     char *dataPtr);
  24.  
  25. extern long
  26. Compress(char *baseAddr,short rowBytes,char *pBaseAddr,short pRowBytes,
  27.     short width,short height,long spatialQ,long temporalQ,char *dataPtr,
  28.     Fixed *similarityP,SharedGlobals *glob);
  29.     
  30.  
  31.  
  32.  
  33. /*
  34.     Our data structure declarations
  35. */
  36.  
  37.  
  38.  
  39.  
  40.  
  41.  
  42. /* Function prototypes to keep the compiler smiling. */
  43.  
  44. pascal ComponentResult
  45. DRAWTEXTCODEC(ComponentParameters *params,char **storage);
  46.  
  47. pascal ComponentResult
  48. OpenCodec(ComponentInstance self);
  49.  
  50. pascal ComponentResult
  51. CloseCodec(Handle storage,ComponentInstance self);
  52.  
  53. pascal ComponentResult
  54. CanDoSelector(short selector);
  55.  
  56. pascal ComponentResult 
  57. GetVersion();
  58.  
  59. pascal void
  60. CompressStrip(char *data,char *baseAddr,short rowBytes,short w,SharedGlobals *sg);
  61.  
  62. pascal void
  63. DecompressStrip(char *data,char *baseAddr,short rowBytes,short w,SharedGlobals *sg);
  64.  
  65.  
  66.  
  67. /************************************************************************************ 
  68.  *    This is the main dispatcher for our codec. All calls from the codec manager
  69.  *    will come through here, with a unique selector and corresponding parameter block.
  70.  *
  71.  *    This routine must be first in the code segment of the codec thing.
  72.  */
  73.  
  74. pascal ComponentResult
  75. DRAWTEXTCODEC(ComponentParameters *params,char **storage)
  76. {
  77.     /*    If the selector is less than zero, it's a Component manager selector.    */
  78.     
  79.     if ( params->what < 0  ) { 
  80.         switch ( params->what ) {
  81.         case kComponentOpenSelect:
  82.             return CallComponentFunction(params, (ComponentFunction) OpenCodec );
  83.  
  84.         case    kComponentCloseSelect:
  85.             return CallComponentFunctionWithStorage(storage,params,(ComponentFunction) CloseCodec );
  86.             
  87.         case    kComponentCanDoSelect:
  88.             return CallComponentFunction(params, (ComponentFunction) CanDoSelector);
  89.  
  90.         case kComponentVersionSelect : 
  91.             return CallComponentFunction(params, (ComponentFunction) GetVersion);
  92.  
  93.         default :
  94.             return (paramErr);
  95.         }
  96.     }
  97.     
  98.     /*
  99.      *    Here we dispatch the rest of our calls. We use the magic thing manager routine which
  100.      *    calls our subroutines with the proper parameters. The prototypes are in Image Codec.h.
  101.      */
  102.     
  103.     switch ( params->what ) {
  104.     case codecPreCompress:    
  105.         return CallComponentFunctionWithStorage(storage,params,(ComponentFunction)CDPreCompress);
  106.         
  107.     case codecBandCompress:
  108.         return CallComponentFunctionWithStorage(storage,params,(ComponentFunction)CDBandCompress);
  109.         
  110.     case codecPreDecompress:
  111.         return CallComponentFunctionWithStorage(storage,params,(ComponentFunction)CDPreDecompress);
  112.  
  113.     case codecBandDecompress:
  114.         return CallComponentFunctionWithStorage(storage,params,(ComponentFunction)CDBandDecompress);
  115.  
  116.     case codecCDSequenceBusy:
  117.         return 0;                    /* our codec is never asynchronously busy */
  118.  
  119.     case codecGetCodecInfo:
  120.         return CallComponentFunctionWithStorage(storage,params,(ComponentFunction)CDGetCodecInfo);
  121.         
  122.     case codecGetCompressedImageSize:
  123.         return CallComponentFunctionWithStorage(storage,params,(ComponentFunction)CDGetCompressedImageSize);
  124.  
  125.     case codecGetMaxCompressionSize:
  126.         return CallComponentFunctionWithStorage(storage,params,(ComponentFunction)CDGetMaxCompressionSize);
  127.  
  128.     case codecGetCompressionTime:
  129.         return CallComponentFunctionWithStorage(storage,params,(ComponentFunction)CDGetCompressionTime);
  130.  
  131.     case codecGetSimilarity:
  132.         return CallComponentFunctionWithStorage(storage,params,(ComponentFunction)CDGetSimilarity);
  133.  
  134.     case codecTrimImage:
  135.         return CallComponentFunctionWithStorage(storage,params,(ComponentFunction)CDTrimImage);
  136.     
  137.     default:
  138.         return(paramErr);
  139.     }    
  140. }
  141.  
  142.  
  143. /************************************************************************************ 
  144.  *    This gets called when the thing instance is opened. We allocate our shared storage at this
  145.  *    point. 
  146.  
  147.  *    If we have shared globals, we check if they exist, otherwise we allocate
  148.  *  them and set the ComponentRefCon so that other instances can use them.
  149.  *
  150.  *    The shared globals hold our CodecInfo struct, which we read from our resource file,
  151.  *  and some tables that we use for speed. If we cant get the tables we can work without
  152.  *  them. All items in the shared globals are made purgeable when the last of our 
  153.  *    instances is closed. If our component was loaded in the application heap ( because
  154.  *    there was no room in the system heap) then we keep our shared storage in the app heap.
  155.  *
  156.  *  We keep a pointer to the shared globals in our instance globals so that other calls can get to them.
  157.  */
  158.  
  159.  
  160. ComponentResult
  161. InitSharedTables(Globals **glob,ComponentInstance self)
  162. {
  163.     SharedGlobals    *sGlob;
  164.     long            i,j,*lp;
  165.     char            *cp;
  166.     short            resFile;
  167.     THz                saveZone;
  168.     Boolean            inAppHeap;
  169.     OSErr            result = noErr;
  170.         
  171.      
  172.     saveZone = GetZone();
  173.     inAppHeap = ( GetComponentInstanceA5(self) != 0 );
  174.     if ( !inAppHeap )
  175.         SetZone(SystemZone());
  176.     if ( (sGlob=(SharedGlobals*)GetComponentRefcon((Component)self)) == nil  ) {
  177.         if ( (sGlob = (SharedGlobals*)NewPtrClear(sizeof(SharedGlobals))) == nil ) { 
  178.             result = MemError();
  179.             goto obail;
  180.         } 
  181.         SetComponentRefcon((Component)self,(long)sGlob);
  182.     }
  183.  
  184.     (*glob)->sharedGlob = sGlob;    // keep this around where it's easy to get at
  185.     
  186.  
  187.     if ( sGlob->info == nil || *(Handle)sGlob->info == nil  )  {
  188.         if ( sGlob->info ) 
  189.             DisposHandle((Handle)sGlob->info);
  190.  
  191.         /* Get the CodecInfo struct which we keep in our resource fork */
  192.         
  193.         resFile = OpenComponentResFile((Component)self);
  194. #ifndef    THINK_C        // if running linked this will return an error since the res file is already open
  195.         if ( (result=ResError() ) != 0 ) 
  196.             goto obail;
  197. #endif    THINK_C
  198.         sGlob->info = (CodecInfo **) GetResource(codecInfoResourceType,128);
  199.         if ( sGlob->info == nil ) {
  200.             CloseComponentResFile(resFile);
  201.             result = ResError();
  202.             goto obail;
  203.         }
  204.         LoadResource((Handle)sGlob->info);
  205.         if ( ResError() ) {
  206.             sGlob->info = nil;
  207.             CloseComponentResFile(resFile);
  208.             result = ResError();
  209.             goto obail;
  210.         }
  211.         DetachResource((Handle)sGlob->info);
  212.         CloseComponentResFile(resFile);
  213.     }
  214.     HNoPurge((Handle)sGlob->info);
  215.     
  216. obail:
  217.  
  218.     SetZone(saveZone);
  219.     if ( result != noErr && sGlob != nil ) {
  220.         if ( sGlob->info )
  221.             DisposHandle((Handle)sGlob->info);
  222.         DisposPtr((Ptr)sGlob);
  223.         SetComponentRefcon((Component)self,(long)nil);
  224.     }
  225.     return(result);
  226. }
  227.  
  228. /************************************************************************************ 
  229.  *    This gets called when the thing instance is opened. We allocate our storage at this
  230.  *    point. If we have shared globals, we check if they exist, and put a pointer to them 
  231.  *    in our instance globals so that other calls can get to them.
  232.  */
  233.  
  234. pascal ComponentResult
  235. OpenCodec(ComponentInstance self)
  236. {
  237.     ComponentResult result;
  238.     Globals             **glob;
  239.     ComponentDescription ci;
  240.     
  241.     /* 
  242.         First we allocate shared storage. This should be a handle to any
  243.         kind of data used by the thing instance. They should be allocated
  244.         in the current heap.
  245.     
  246.     */     
  247.          
  248.     if ( (glob = (Globals **)NewHandleClear(sizeof(Globals))) == nil )  {
  249.         return(MemError());
  250.     }
  251.     SetComponentInstanceStorage(self,(Handle)glob);
  252.     
  253.     /*     Check and initialize our shared globals */
  254.  
  255.     (*glob)->self = self;
  256.     result = InitSharedTables(glob,self);
  257.     
  258.     
  259.     return result;
  260. }
  261.  
  262.  
  263. /************************************************************************************ 
  264.  *    This gets called when the thing instance is closed. We need to get rid of any 
  265.  *    instance storage here. 
  266.  */
  267.  
  268. pascal ComponentResult
  269. CloseCodec(Handle storage,ComponentInstance self)
  270. {
  271.     SharedGlobals    *sGlob;
  272.     long            i;
  273.     Globals            **glob = (Globals **)storage;
  274.         
  275.     /*    If we are closing our last instance 
  276.         then we make the shared global items purgeable to
  277.         speed things up next instance.
  278.      */
  279.     
  280.     if ( CountComponentInstances((Component)self) == 1) {
  281.         if ( (sGlob=(SharedGlobals*)(*glob)->sharedGlob) != nil  ) {
  282.             if ( sGlob->info )
  283.                 HPurge((Handle)sGlob->info);
  284.             if ( sGlob->tableWorld ) {
  285.                 DisposeGWorld(sGlob->tableWorld );
  286.                 sGlob->tableWorld = nil;
  287.             }
  288.         }
  289.     }
  290.     if ( glob )     {
  291.         DisposHandle((Handle)glob);
  292.     }
  293.     return(noErr);
  294. }
  295.  
  296.  
  297.  
  298. /************************************************************************************ 
  299.  *     Return true if we can handle the selector, otherwise false.
  300.  */
  301.  
  302. pascal ComponentResult
  303. CanDoSelector(short selector)
  304. {    
  305.     switch(selector) {
  306.         case kComponentOpenSelect:
  307.         case kComponentCloseSelect:
  308.         case kComponentCanDoSelect:
  309.         case kComponentVersionSelect : 
  310.         case codecPreCompress:
  311.         case codecBandCompress:
  312.         case codecPreDecompress:
  313.         case codecBandDecompress:
  314.         case codecCDSequenceBusy:
  315.         case codecGetCodecInfo:
  316.         case codecGetCompressedImageSize:
  317.         case codecGetMaxCompressionSize:
  318.         case codecGetCompressionTime:
  319.         case codecGetSimilarity:
  320.         case codecTrimImage:
  321.             return(true);
  322.         default:
  323.             return (false);
  324.     }
  325. }
  326.  
  327.  
  328. /************************************************************************************ 
  329.  *    Return the version of this component ( defines interface ) and revision level
  330.  *    of the code.
  331.  */
  332.  
  333. pascal ComponentResult 
  334. GetVersion()
  335. {
  336.     return ((1<<16) | 1);        /* interface version in hi word, code rev in lo word  */
  337. }
  338.  
  339.  
  340. /************************************************************************************ 
  341.  *    CDPreCompress gets called before an image is compressed, or whenever the source pixmap
  342.  *    pixel size changes when compressing a sequence. We return information about
  343.  *    how we can compress the image to the codec manager, so that it can fit the source data
  344.  *    to our requirements. The ImageDescriptor is already filled in, so we can use it for 
  345.  *    reference (or even add to it ). PixelSize is the pixel depth of the source pixmap, we
  346.  *    use this as a reference for deciding what we can do. The other parameters return information
  347.  *    to the CodecManager about what we can do. We can also do setup here if we want to.
  348.  */
  349.  
  350. pascal long
  351. CDPreCompress(Handle storage,register CodecCompressParams *p)
  352. {
  353.     Globals                **glob  = (Globals **)storage;
  354.     CodecCapabilities *capabilities = p->capabilities;
  355.  
  356.     /*
  357.      *    First we return which depth input pixels we can deal with - based on what the
  358.      *    app has available - we can only work with 32 bit input pixels.
  359.      */
  360.        
  361.     switch ( (*p->imageDescription)->depth )  {
  362.         case 1:
  363.             capabilities->wantedPixelSize = 1;
  364.             break;
  365.         default:
  366.             return(codecConditionErr);
  367.             break;
  368.     }
  369.  
  370.     /* if the buffer gets banded,  return the smallest one we can deal with */
  371.     
  372.     capabilities->bandMin = FONT_HEIGHT;
  373.  
  374.     /* if the buffer gets banded, return the increment it be should grown */
  375.  
  376.     capabilities->bandInc = FONT_HEIGHT;
  377.     
  378.     
  379.     /*
  380.      *    If a codec needs the dimensions of the source pixmap to be of certain multiples
  381.      *    it can ask for the image to be extended out (via pixel replication) vertically
  382.      *    and/or horizontally.
  383.      */
  384.  
  385.     if ( (*p->imageDescription)->width % FONT_WIDTH )
  386.         capabilities->extendWidth = FONT_WIDTH & (FONT_WIDTH - ((*p->imageDescription)->width % FONT_WIDTH));
  387.     if ( (*p->imageDescription)->height % FONT_HEIGHT )
  388.         capabilities->extendHeight = FONT_HEIGHT & (FONT_HEIGHT - ((*p->imageDescription)->height % FONT_HEIGHT));
  389.     
  390.     if ( (*glob)->sharedGlob->tableWorld == nil )    
  391.         InitCharTab((*glob)->sharedGlob,(*glob)->self);
  392.  
  393.     return(noErr);
  394. }
  395.  
  396.  
  397. /************************************************************************************ 
  398.  *    CDBandCompress gets called when the codec manager wants us to compress an image, or a horizontal 
  399.  *    band of an image. The pixel data at sBaseAddr is guaranteed to conform to the criteria we 
  400.  *    demanded in BeginCompress.
  401.  */
  402.  
  403. pascal long
  404. CDBandCompress(Handle storage,register CodecCompressParams *p)
  405. {
  406.     short                width,height;
  407.     Ptr                    cDataPtr,dataStart;
  408.     short                depth;
  409.     Rect                sRect;
  410.     long                offsetH,offsetV;
  411.     Globals                **glob  = (Globals **)storage;
  412.     register char         *baseAddr;
  413.     long                numLines,numStrips;
  414.     short                rowBytes;
  415.     char                mmuMode = 1;
  416.     register short        y;
  417.     ImageDescription    **desc = p->imageDescription;
  418.     OSErr                result = noErr;
  419.     Fixed                simil;
  420.     long                csize;
  421.     CodecQ                spatialQ,temporalQ;
  422.     
  423.     
  424.     
  425.     /*    If there is a progress proc, give it an open call at the start of this band. */
  426.  
  427.     if (p->progressProcRecord.progressProc)
  428.         p->progressProcRecord.progressProc(codecProgressOpen,0,
  429.             p->progressProcRecord.progressRefCon);
  430.  
  431.     width = (*desc)->width;
  432.     height = (*desc)->height;
  433.     depth = (*desc)->depth;
  434.     dataStart = cDataPtr = p->data;
  435.     spatialQ = p->spatialQuality;
  436.     temporalQ = p->temporalQuality;
  437.     
  438.     /* figure out offset to first pixel in baseAddr from the pixelsize and bounds */
  439.  
  440.     rowBytes = p->srcPixMap.rowBytes & 0x3fff;
  441.     sRect =  p->srcPixMap.bounds;
  442.     numLines = p->stopLine - p->startLine;            /* number of scanlines in this band */
  443.     numStrips = numLines/FONT_HEIGHT;                /* number of strips in this band */
  444.     
  445.     /* adjust the source baseAddress to be at the beginning of the desired rect */
  446.  
  447.     switch ( p->srcPixMap.pixelSize ) {
  448.     case 1:
  449.         offsetH = sRect.left>>3;                    /* 8 pixels = 1 byte */
  450.         break;
  451.     default:
  452.         result = codecErr;
  453.         goto bail;
  454.     }
  455.     offsetV = sRect.top * rowBytes;
  456.     baseAddr = p->srcPixMap.baseAddr + offsetH + offsetV;
  457.  
  458.  
  459.     if ( p->conditionFlags & codecConditionFirstBand) {
  460.         (*glob)->totalSize = 0;
  461.     }
  462.     else { 
  463.         /* if there is not a flush proc, adjust the pointer to the next band */
  464.         
  465.         if (  p->flushProcRecord.flushProc == nil )
  466.             cDataPtr += (*glob)->totalSize;
  467.     }
  468.  
  469.     /* do the slower flush/progress case if we have too */
  470.     
  471.     if (  p->flushProcRecord.flushProc  || p->progressProcRecord.progressProc ) {
  472.         SharedGlobals *sg = (*glob)->sharedGlob;
  473.  
  474.  
  475.         for ( y=0; y < numStrips; y++) {
  476.             SwapMMUMode(&mmuMode);
  477.             csize = Compress(baseAddr,rowBytes,nil,0,width/FONT_WIDTH,1,spatialQ,temporalQ,
  478.                     cDataPtr,&simil,sg);
  479.             SwapMMUMode(&mmuMode);
  480.             baseAddr += rowBytes*FONT_HEIGHT;
  481.             if ( p->flushProcRecord.flushProc ) { 
  482.                 if ( (result=p->flushProcRecord.flushProc(cDataPtr,csize,
  483.                         p->flushProcRecord.flushRefCon)) != noErr) {
  484.                     result = codecSpoolErr;
  485.                     goto bail;
  486.                 }
  487.             } else {
  488.                 cDataPtr += csize;
  489.             }
  490.             (*glob)->totalSize += csize;
  491.             if (p->progressProcRecord.progressProc) {
  492.                 if ( (result=p->progressProcRecord.progressProc(codecProgressUpdatePercent,
  493.                     FixDiv(y,numStrips),p->progressProcRecord.progressRefCon)) != noErr ) {
  494.                         result = codecAbortErr;
  495.                         goto bail;
  496.                     }
  497.             }
  498.         }
  499.     } else 
  500.     {
  501.         SharedGlobals *sg = (*glob)->sharedGlob;
  502.  
  503.         SwapMMUMode(&mmuMode);
  504.         csize = Compress(baseAddr,rowBytes,nil,0,width/FONT_WIDTH,numStrips,spatialQ,
  505.             temporalQ,cDataPtr,&simil,sg);
  506.         SwapMMUMode(&mmuMode);
  507.         cDataPtr += csize;
  508.         (*glob)->totalSize += csize;
  509.     }
  510.  
  511.     /*
  512.     
  513.         return size and similarity on the last band 
  514.         
  515.     */
  516.     
  517.     if ( p->conditionFlags & codecConditionLastBand ) {
  518.         (*p->imageDescription)->dataSize = (*glob)->totalSize;    /* return the actual size of the compressed data */
  519.         p->similarity = 0;                                        /* we don't do frame differencing */
  520.     }
  521.     
  522. bail:
  523.     /*    If there is a progress proc, give it a close call at the end of this band. */
  524.  
  525.     if (p->progressProcRecord.progressProc)
  526.         p->progressProcRecord.progressProc(codecProgressClose,0,
  527.             p->progressProcRecord.progressRefCon);
  528.         
  529.     return(result);
  530. }
  531.  
  532.  
  533.  
  534. /************************************************************************************ 
  535.  *    CDPreDecompress gets called before an image is decompressed. We return information about
  536.  *    how we can decompress the image to the codec manager, so that it can fit the destination data
  537.  *    to our requirements. 
  538.  */
  539.  
  540. pascal long
  541. CDPreDecompress(Handle storage,register CodecDecompressParams *p)
  542. {
  543.     register CodecCapabilities    *capabilities = p->capabilities;
  544.     Rect    dRect = p->srcRect;
  545.     
  546.     /*    Check if the matrix is okay for us. We don't do anything fancy. */
  547.     
  548.     if ( !TransformRect(p->matrix,&dRect,nil) )
  549.         return(codecConditionErr);
  550.  
  551.  
  552.     /*    Decide which depth compressed data we can deal with. */
  553.     
  554.     switch ( (*p->imageDescription)->depth )  {
  555.         case 1:
  556.             break;
  557.         default:
  558.             return(codecConditionErr);
  559.             break;
  560.     }
  561.     
  562.     /*    We can deal only 1 bit pixels. */
  563.  
  564.     capabilities->wantedPixelSize = 1;    
  565.         
  566.     capabilities->bandMin = FONT_HEIGHT;
  567.  
  568.     capabilities->bandInc = FONT_HEIGHT;
  569.     
  570.     /*    If we needed our pixels to be aligned on some integer multiple we would set these to
  571.      *    the number of pixels we need the dest extended by. If we dont care, or we take care of
  572.      *  it ourselves we set them to zero.
  573.      */
  574.  
  575.     if ( (*p->imageDescription)->width % FONT_WIDTH )
  576.         capabilities->extendWidth = FONT_WIDTH & (FONT_WIDTH - ((*p->imageDescription)->width % FONT_WIDTH));
  577.     if ( (*p->imageDescription)->height % FONT_HEIGHT )
  578.         capabilities->extendHeight = FONT_HEIGHT & (FONT_HEIGHT - ((*p->imageDescription)->height % FONT_HEIGHT));
  579.     
  580.     return(noErr);
  581. }
  582.  
  583.  
  584. /************************************************************************************ 
  585.  *    CDBandDecompress gets called when the codec manager wants us to decompress an image or a horizontal 
  586.  *    band of an image. The pixel data at baseAddr is guaranteed to conform to the criteria we 
  587.  *    demanded in BeginDecompress. If maskIn is true, then the mask data at mBaseAddr is valid, and
  588.  *    we need to clear bits in it that correspond to any pixels in the destination we do not want to 
  589.  *    change. ( We always write all pixels, so we dont care. This mode is important only for those
  590.  *    codecs that have frame differencing and don't always write all the pixels. )
  591.  */
  592.  
  593. pascal long
  594. CDBandDecompress(Handle storage,register CodecDecompressParams *p)
  595. {
  596.     Rect                dRect;
  597.     long                offsetH,offsetV;
  598.     Globals                **glob  = (Globals **)storage;
  599.     long                numLines,numStrips;
  600.     short                rowBytes;
  601.     long                stripBytes;
  602.     short                width;
  603.     register short        y;
  604.     register char        *baseAddr;
  605.     char                *cDataPtr;
  606.     char                mmuMode = 1;
  607.     OSErr                result = noErr;
  608.     long                csize;
  609.     
  610.     /*    Calculate the real base address based on the bounds rect. If it's not 
  611.         a linear transformation, we dont do it. */
  612.  
  613.     dRect = p->srcRect;
  614.     if ( !TransformRect(p->matrix,&dRect,nil) )
  615.         return(paramErr);
  616.  
  617.     /*    If there is a progress proc, give it an open call at the start of this band. */
  618.  
  619.     if (p->progressProcRecord.progressProc)
  620.         p->progressProcRecord.progressProc(codecProgressOpen,0,
  621.             p->progressProcRecord.progressRefCon);
  622.     
  623.     
  624.     /* initialize some local variables */
  625.     
  626.     width = (*p->imageDescription)->width;
  627.     rowBytes = p->dstPixMap.rowBytes;                    
  628.     numLines = p->stopLine - p->startLine;                /* number of scanlines in this band */
  629.     numStrips = numLines/FONT_HEIGHT;                    /* number of strips in this band */
  630.     stripBytes = (width + (FONT_WIDTH-1))/FONT_WIDTH;    /* number of bytes in one strip of blocks */
  631.     cDataPtr = p->data;
  632.     
  633.     /* adjust the destination baseaddress to be at the beginning of the desired rect */
  634.     
  635.     offsetH = (dRect.left - p->dstPixMap.bounds.left);
  636.     switch (  p->dstPixMap.pixelSize ) {
  637.     case 1:
  638.         offsetH >>= 3;                    /* 8 pixel = 1 bytes */
  639.         break;
  640.     default:
  641.         result = codecErr;                /* we dont handle these cases, thow we could */
  642.         goto bail;
  643.     }
  644.     offsetV = (dRect.top - p->dstPixMap.bounds.top) * rowBytes;
  645.     baseAddr = p->dstPixMap.baseAddr + offsetH + offsetV;
  646.  
  647.  
  648.     /* 
  649.      *    If we are skipping some data, we just skip it here. We can tell because
  650.      *    firstBandInFrame says this is the first band for a new frame, and
  651.      *    if startLine is not zero, then that many lines were clipped out.
  652.      */
  653.  
  654.     if ( (p->conditionFlags & codecConditionFirstBand) ) {
  655.         cDataPtr += p->startLine * stripBytes;
  656.     }
  657.     
  658.     /*
  659.      *    If theres a dataproc spooling the data to us, then we have to do the data
  660.      *    in whatever size chunks they want to give us, or if there is a progressProc
  661.      *  make sure to call it as we go along.
  662.      */
  663.  
  664.     
  665.     if ( p->dataProcRecord.dataProc || p->progressProcRecord.progressProc ) {
  666.         SharedGlobals *sg = (*glob)->sharedGlob;
  667.     
  668.         for (y=0; y < numStrips; y++) {
  669.             if (p->dataProcRecord.dataProc) {
  670.                 if ( (result=p->dataProcRecord.dataProc(&cDataPtr,stripBytes,
  671.                         p->dataProcRecord.dataRefCon)) != noErr ) {
  672.                     result = codecSpoolErr;
  673.                     goto bail;
  674.                 }
  675.             }
  676.             SwapMMUMode(&mmuMode);
  677.             csize = Decompress(baseAddr,rowBytes,width/FONT_WIDTH,1,cDataPtr);
  678.             SwapMMUMode(&mmuMode);
  679.             baseAddr += rowBytes*FONT_HEIGHT;
  680.             cDataPtr += csize;
  681.             if (p->progressProcRecord.progressProc) {
  682.                 if ( (result=p->progressProcRecord.progressProc(codecProgressUpdatePercent,
  683.                     FixDiv(y, numStrips),p->progressProcRecord.progressRefCon)) != noErr ) {
  684.                     result = codecAbortErr;
  685.                      goto bail;
  686.                 }
  687.             }
  688.         }
  689.     
  690.     
  691.     /* 
  692.      *
  693.      * otherwise - do the fast case. 
  694.      *
  695.      */
  696.          
  697.     } else
  698.      {
  699.         
  700.         SwapMMUMode(&mmuMode);
  701.         csize = Decompress(baseAddr,rowBytes,width/FONT_WIDTH,numStrips,cDataPtr);
  702.         SwapMMUMode(&mmuMode);
  703.         cDataPtr += csize;
  704.     }
  705.     
  706.     /* 
  707.      *
  708.      *  IMPORTANT: update pointer to data in params, so when we get the  next
  709.      *  band we'll be at the right place in our data.
  710.      *  
  711.      */
  712.     
  713.     p->data = cDataPtr;
  714.     
  715.     if ( p->conditionFlags & codecConditionLastBand ) {
  716.         /* Tie up any loose ends on the last band of the frame, if we had any */
  717.     }
  718.  
  719. bail:
  720.     /*    If there is a progress proc, give it a close call at the end of this band. */
  721.  
  722.     if (p->progressProcRecord.progressProc)
  723.         p->progressProcRecord.progressProc(codecProgressClose,0,
  724.             p->progressProcRecord.progressRefCon);
  725.     return(result);
  726. }
  727.  
  728.  
  729. /************************************************************************************ 
  730.  *    CDGetCodecInfo allows us to return information about ourselves to the codec manager.
  731.  *    
  732.  *    There will be a tool for determining appropriate values for the accuracy, speed
  733.  *    and level information. For now we estimate with scientific wild guessing.
  734.  *
  735.  *  The info is stored as a resource in the same file with our component.
  736.  */
  737.  
  738. pascal ComponentResult
  739. CDGetCodecInfo(Handle storage,CodecInfo *info)
  740. {
  741.     Globals **glob = (Globals **)storage;
  742.  
  743.     if ( info == nil ) 
  744.         return(paramErr);
  745.     BlockMove((Ptr)*((*glob)->sharedGlob)->info,(Ptr)info,sizeof(CodecInfo));
  746.     return(noErr);
  747. }
  748.  
  749.  
  750. /************************************************************************************ 
  751.  *    When CDGetSimilarity is called, we return the percent of the compressed image A that
  752.  *    is different from compressed image B. This can be used by applications that use sequence
  753.  *    dynamics as an indicator for editing image sequences.
  754.  *    
  755.  *    If the codec cannot do a direct similarity comparison, the ICM decompresses image A and
  756.  *    do a comparison with image B.  This call is provided so that a codec can save the time
  757.  *    of the intermediate decompress if it can do the comparison directly.
  758.  */
  759.  
  760. pascal ComponentResult
  761. CDGetSimilarity(Handle storage,PixMapHandle src,const Rect *srcRect,ImageDescriptionHandle desc,
  762.                 Ptr data,Fixed *similarity)
  763. {
  764. #pragma    unused(storage,src,srcRect,desc,data,dif,refcon)
  765.  
  766.     /*    This call is not implemented yet, which is okay, because its not used very much and is not mandatory */
  767.  
  768.     return(codecUnimpErr);
  769. }
  770.  
  771.  
  772. /************************************************************************************ 
  773.  *    When CDGetCompressedImageSize is called, we return the size in bytes of the given compressed
  774.  *    data ( for one image frame).
  775.  */
  776.  
  777. pascal ComponentResult
  778. CDGetCompressedImageSize(Handle storage,ImageDescriptionHandle desc,Ptr data,long dataSize,
  779.     DataProcRecordPtr dataProc,long *size)
  780. {
  781. #pragma    unused(storage,data,dataSize,dataProc)
  782.     
  783.         
  784.     short width = (*desc)->width;
  785.     short height = (*desc)->height;
  786.     if ( size == nil )
  787.         return(paramErr);
  788.  
  789.     /*    we always end up with a fixed size. If we did not, we would return the worst case size */
  790.     
  791.     *size = ((width + (FONT_WIDTH-1))/FONT_WIDTH) * ((height+(FONT_HEIGHT-1))/FONT_HEIGHT);    
  792.     return(noErr);
  793. }
  794.  
  795.  
  796. /************************************************************************************ 
  797.  *    When CDGetMaxCompressionSize is called, we return the maximum size the compressed data for
  798.  *    the given image would be in bytes.
  799.  */
  800.  
  801. pascal ComponentResult
  802. CDGetMaxCompressionSize(Handle storage,PixMapHandle src,const Rect *srcRect,short depth,
  803.     CodecQ quality,long *size)
  804. {
  805. #pragma    unused(storage,src,depth,quality)
  806.     
  807.     short width = srcRect->right - srcRect->left;
  808.     short height = srcRect->bottom - srcRect->top;
  809.  
  810.     /*    we always end up with a fixed size. If we did not, we would return the worst case size */
  811.     
  812.     *size = 100 + ((width + (FONT_WIDTH-1))/FONT_WIDTH) * ((height+(FONT_HEIGHT-1))/FONT_HEIGHT);    
  813.  
  814.     return(noErr);
  815. }
  816.  
  817.  
  818. /************************************************************************************ 
  819.  *    When CDGetCompressionTime is called, we return the approximate time for compressing
  820.  *    the given image would be in milliseconds. We also return the closest actual quality
  821.  *    we can handle for the requested value.
  822.  */
  823.  
  824. pascal ComponentResult
  825. CDGetCompressionTime(Handle storage,PixMapHandle src,const Rect *srcRect,short depth,
  826.         CodecQ *spatialQuality,CodecQ *temporalQuality,unsigned long *time)
  827. {
  828. #pragma    unused(storage,src,srcRect,depth)
  829.  
  830.     if (time)
  831.         *time = 0;                                    /* we don't know how many msecs */
  832.  
  833.     if ( spatialQuality ) {
  834.         if ( *spatialQuality <= codecLowQuality ) {
  835.             *spatialQuality = codecLowQuality;
  836.         }
  837.         else if ( *spatialQuality <= codecNormalQuality ) {
  838.             *spatialQuality = codecNormalQuality;
  839.         } else {
  840.             *spatialQuality = codecHighQuality;
  841.         }
  842.     }
  843.     if ( temporalQuality ) 
  844.         *temporalQuality = 0;
  845.     return(noErr);
  846. }
  847.  
  848.  
  849. /************************************************************************************ 
  850.  *    When CDTrimImage is called, we take the given compressed data and return only the portion
  851.  *    which is represented by the trimRect. We can return a little more if we have too, but we
  852.  *    need only return enough so that the image in trimRect is properly displayed. We then
  853.  *    adjust the rectangle to corresond to the same rectangle in the new trimmed data.
  854.  */
  855.  
  856. pascal ComponentResult
  857. CDTrimImage(Handle storage,ImageDescriptionHandle desc,Ptr inData,long inDataSize,
  858.         DataProcRecordPtr dataProc,Ptr outData,long outDataSize,FlushProcRecordPtr flushProc,
  859.         Rect *trimRect,ProgressProcRecordPtr progressProc)
  860. {
  861.  
  862.     return(codecUnimpErr);
  863.  
  864. }
  865.